#include "pika_hal_cqueue.h"

pika_hal_cqueue_t* pika_hal_cqueue_create(size_t capacity, size_t elementSize) {
    pika_hal_cqueue_t* cque = (pika_hal_cqueue_t*)pikaMalloc(sizeof(pika_hal_cqueue_t));
    if (NULL == cque) {
        return PIKA_RES_ERR_MEMORY_ERROR;
    }
    return pika_hal_cqueue_init(cque, capacity, elementSize);
}

// 初始化一个已分配的循环队列
int pika_hal_cqueue_init(pika_hal_cqueue_t* cque, size_t capacity, size_t elementSize) {
    if (NULL == cque) {
        return PIKA_RES_ERR_ASSERT;
    }
    cque->buffer = NULL; //先赋NULL，不然后面没初始化也判不到NULL
#if PIKA_HAL_CQUEUE_MUTEX_ENABLE
    int err = pika_platform_thread_lock_init(&cque->lock);
    if (err < 0){
        return PIKA_RES_ERR_MEMORY_ERROR;
    }
    pika_platform_thread_lock_acquire(&cque->lock, pika_true, -1);
#endif
    char* buffer = (char*)pikaMalloc(capacity * elementSize);

    if (buffer == NULL){
#if PIKA_HAL_CQUEUE_MUTEX_ENABLE
        pika_platform_thread_lock_destroy(&cque->lock);
#endif
        return PIKA_RES_ERR_MEMORY_ERROR;
    }
    cque->head = 0;
    cque->tail = 0;
    cque->count = 0;
    cque->capacity = capacity;
    cque->elementSize = elementSize;
    cque->buffer = buffer;
#if PIKA_HAL_CQUEUE_MUTEX_ENABLE
    pika_platform_thread_lock_release(&cque->lock);
#endif
    return PIKA_RES_OK;
}

// 向队列尾部添加一个元素
int pika_hal_cqueue_appendTail(pika_hal_cqueue_t* cque, const void* value) {
    int ret = PIKA_RES_OK;
#if PIKA_HAL_CQUEUE_MUTEX_ENABLE
    pika_platform_thread_lock_acquire(&cque->lock, pika_true, -1);
#endif
    if (cque->count == cque->capacity) {
        ret = PIKA_RES_ERR_FULL; //队列已满
        goto __exit;
    }

    memcpy(cque->buffer + (cque->tail * cque->elementSize), value, cque->elementSize);
    cque->tail = (cque->tail + 1) % cque->capacity;
    cque->count++;
__exit:
#if PIKA_HAL_CQUEUE_MUTEX_ENABLE
    pika_platform_thread_lock_release(&cque->lock);
#endif
    return ret;
}

// 向队列头部添加一个元素
int pika_hal_cqueue_appendHead(pika_hal_cqueue_t* cque, const void* value) {
    int ret = PIKA_RES_OK;
#if PIKA_HAL_CQUEUE_MUTEX_ENABLE
    pika_platform_thread_lock_acquire(&cque->lock, pika_true, -1);
#endif
    if (cque->count == cque->capacity) {
        ret = PIKA_RES_ERR_FULL;  // 队列已满
        goto __exit;
    }

    cque->head = (cque->head - 1 + cque->capacity) % cque->capacity;
    memcpy(cque->buffer + (cque->head * cque->elementSize), value, cque->elementSize);
    cque->count++;
__exit:
#if PIKA_HAL_CQUEUE_MUTEX_ENABLE
    pika_platform_thread_lock_release(&cque->lock);
#endif
    return ret;
}

// 从队列头部移除一个元素
int pika_hal_cqueue_popHead(pika_hal_cqueue_t* cque, void* value) {
    int ret = PIKA_RES_OK;
#if PIKA_HAL_CQUEUE_MUTEX_ENABLE
    pika_platform_thread_lock_acquire(&cque->lock, pika_true, -1);
#endif
    if (cque->count == 0) {
        ret = PIKA_RES_ERR_EMPTY; //队列为空
        goto __exit;
    }

    memcpy(value, cque->buffer + (cque->head * cque->elementSize), cque->elementSize);
    cque->head = (cque->head + 1) % cque->capacity;
    cque->count--;
__exit:
#if PIKA_HAL_CQUEUE_MUTEX_ENABLE
    pika_platform_thread_lock_release(&cque->lock);
#endif
    return ret;
}

// 从队列尾部移除一个元素
int pika_hal_cqueue_popTail(pika_hal_cqueue_t* cque, void* value) {
    int ret = PIKA_RES_OK;
#if PIKA_HAL_CQUEUE_MUTEX_ENABLE
    pika_platform_thread_lock_acquire(&cque->lock, pika_true, -1);
#endif
    if (cque->count == 0) {
        ret = PIKA_RES_ERR_EMPTY;  // 队列为空
        goto __exit;
    }

    cque->tail = (cque->tail - 1 + cque->capacity) % cque->capacity;
    memcpy(value, cque->buffer + (cque->tail * cque->elementSize), cque->elementSize);
    cque->count--;
__exit:
#if PIKA_HAL_CQUEUE_MUTEX_ENABLE
    pika_platform_thread_lock_release(&cque->lock);
#endif
    return ret;
}

// 查看但不移除队首元素
int pika_hal_cqueue_peekHead(pika_hal_cqueue_t* cque, void* value) {
    if (cque->count == 0) {
        return PIKA_RES_ERR_EMPTY; // 队列为空
    }

#if PIKA_HAL_CQUEUE_MUTEX_ENABLE
    pika_platform_thread_lock_acquire(&cque->lock, pika_true, -1);
#endif
    memcpy(value, cque->buffer + (cque->head * cque->elementSize), cque->elementSize);
#if PIKA_HAL_CQUEUE_MUTEX_ENABLE
    pika_platform_thread_lock_release(&cque->lock);
#endif
    return PIKA_RES_OK;
}

// 查看但不移除队尾元素
int pika_hal_cqueue_peekTail(pika_hal_cqueue_t* cque, void* value) {
    if (cque->count == 0) {
        return PIKA_RES_ERR_EMPTY;  // 队列为空
    }

#if PIKA_HAL_CQUEUE_MUTEX_ENABLE
    pika_platform_thread_lock_acquire(&cque->lock, pika_true, -1);
#endif
    size_t index = (cque->tail - 1 + cque->capacity) % cque->capacity;
    memcpy(value, cque->buffer + (index * cque->elementSize), cque->elementSize);
#if PIKA_HAL_CQUEUE_MUTEX_ENABLE
    pika_platform_thread_lock_release(&cque->lock);
#endif

    return PIKA_RES_OK;
}


// 获取队列中的元素数量
size_t pika_hal_cqueue_getCount(pika_hal_cqueue_t* cque) {
#if PIKA_HAL_CQUEUE_MUTEX_ENABLE
    pika_platform_thread_lock_acquire(&cque->lock, pika_true, -1);
#endif
    size_t count = cque->count;
#if PIKA_HAL_CQUEUE_MUTEX_ENABLE
    pika_platform_thread_lock_release(&cque->lock);
#endif
    return count;
}

// 检查队列是否为空
pika_bool pika_hal_cqueue_isEmpty(pika_hal_cqueue_t* cque) {
#if PIKA_HAL_CQUEUE_MUTEX_ENABLE
    pika_platform_thread_lock_acquire(&cque->lock, pika_true, -1);
#endif
    int res = cque->count == 0;
#if PIKA_HAL_CQUEUE_MUTEX_ENABLE
    pika_platform_thread_lock_release(&cque->lock);
#endif
    return res;
}

// 检查队列是否已满
pika_bool pika_hal_cqueue_isFull(pika_hal_cqueue_t* cque) {
#if PIKA_HAL_CQUEUE_MUTEX_ENABLE
    pika_platform_thread_lock_acquire(&cque->lock, pika_true, -1);
#endif
    int res = cque->count == cque->capacity;
#if PIKA_HAL_CQUEUE_MUTEX_ENABLE
    pika_platform_thread_lock_release(&cque->lock);
#endif
    return res;
}


// 销毁队列并清理内部状态
void pika_hal_cqueue_deinit(pika_hal_cqueue_t* cque) {

#if PIKA_HAL_CQUEUE_MUTEX_ENABLE
    pika_platform_thread_lock_acquire(&cque->lock, pika_true, -1);
#endif
    if(cque->buffer != NULL){
        pikaFree(cque->buffer, cque->capacity * cque->elementSize);
        cque->buffer = NULL;
    }
    
    cque->head = 0;
    cque->tail = 0;
    cque->count = 0;
    cque->capacity = 0;
    cque->elementSize = 0;
#if PIKA_HAL_CQUEUE_MUTEX_ENABLE
    pika_platform_thread_lock_release(&cque->lock);
    pika_platform_thread_lock_destroy(&cque->lock);
#endif
}

void pika_hal_cqueue_delete(pika_hal_cqueue_t* cque){
    pika_hal_cqueue_deinit(cque);
    pikaFree(cque, sizeof(pika_hal_cqueue_t));
}

// 将队列的所有元素复制到指定的缓冲区中，但不移动队列的 head 和 tail
int pika_hal_cqueue_copyAll(pika_hal_cqueue_t* cque, void* destBuffer, int maxElementCount) {
    if (NULL == cque || NULL == destBuffer) {
        return -1; // 参数无效
    }

#if PIKA_HAL_CQUEUE_MUTEX_ENABLE
    pika_platform_thread_lock_acquire(&cque->lock, pika_true, -1);
#endif

    size_t count = cque->count;
    size_t elementSize = cque->elementSize;
    size_t elementsToCopy;

    // 如果 maxElementCount 是 -1，则复制所有元素
    if (maxElementCount < 0) {
        elementsToCopy = count;
    } else {
        elementsToCopy = (size_t)maxElementCount < count ? (size_t)maxElementCount : count;
    }

    size_t copiedBytes = 0;

    // 如果队列为空或没有需要复制的元素，则直接返回成功
    if (count == 0 || elementsToCopy == 0) {
        int ret = 0;
#if PIKA_HAL_CQUEUE_MUTEX_ENABLE
        pika_platform_thread_lock_release(&cque->lock);
#endif
        return ret;
    }

    // 复制数据
    for (size_t i = 0; i < elementsToCopy; ++i) {
        size_t index = (cque->head + i) % cque->capacity;
        memcpy((char*)destBuffer + copiedBytes, cque->buffer + (index * elementSize), elementSize);
        copiedBytes += elementSize;
    }

    int ret = 0;
#if PIKA_HAL_CQUEUE_MUTEX_ENABLE
    pika_platform_thread_lock_release(&cque->lock);
#endif
    return ret;
}